package neatlogic.module.change.stephandler.component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import neatlogic.framework.asynchronization.threadlocal.UserContext;
import neatlogic.framework.change.constvalue.ChangeAuditDetailType;
import neatlogic.framework.change.constvalue.ChangeProcessStepHandlerType;
import neatlogic.framework.change.dto.*;
import neatlogic.framework.common.constvalue.GroupSearch;
import neatlogic.framework.crossover.CrossoverServiceFactory;
import neatlogic.framework.exception.type.ParamNotExistsException;
import neatlogic.framework.exception.util.FreemarkerTransformException;
import neatlogic.framework.file.dao.mapper.FileMapper;
import neatlogic.framework.file.dto.FileVo;
import neatlogic.framework.process.constvalue.ProcessStepMode;
import neatlogic.framework.process.constvalue.ProcessTaskAuditDetailType;
import neatlogic.framework.process.constvalue.ProcessTaskAuditType;
import neatlogic.framework.process.crossover.IProcessStepHandlerCrossoverUtil;
import neatlogic.framework.process.dto.ProcessTaskStepVo;
import neatlogic.framework.process.dto.ProcessTaskStepWorkerVo;
import neatlogic.framework.process.exception.processtask.ProcessTaskException;
import neatlogic.framework.process.stephandler.core.ProcessStepHandlerBase;
import neatlogic.framework.util.FreemarkerUtil;
import neatlogic.module.change.dao.mapper.ChangeMapper;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @ClassName: ChangeCreateProcessComponent
 */
@Service
public class ChangeCreateProcessComponent extends ProcessStepHandlerBase {

    private static final Logger logger = LoggerFactory.getLogger(ChangeCreateProcessComponent.class);

    @Resource
    private ChangeMapper changeMapper;

    @Resource
    private FileMapper fileMapper;

    @Override
    public String getHandler() {
        return ChangeProcessStepHandlerType.CHANGECREATE.getHandler();
    }

    @Override
    public JSONObject getChartConfig() {
        return new JSONObject() {
            {
                this.put("icon", "tsfont-addchange");
                this.put("shape", "L-rectangle:R-rectangle");
                this.put("width", 68);
                this.put("height", 40);
            }
        };
    }

    @Override
    public String getType() {
        return ChangeProcessStepHandlerType.CHANGECREATE.getType();
    }

    @Override
    public ProcessStepMode getMode() {
        return ProcessStepMode.MT;
    }

    @Override
    public String getName() {
        return ChangeProcessStepHandlerType.CHANGECREATE.getName();
    }

    @Override
    public int getSort() {
        return 6;
    }

    @Override
    public boolean isAsync() {
        return false;
    }

    @Override
    public Boolean isAllowStart() {
        return true;
    }

    @Override
    protected int myActive(ProcessTaskStepVo currentProcessTaskStepVo) throws ProcessTaskException {
        try {
            Long id = changeMapper.getChangeIdByProcessTaskStepId(currentProcessTaskStepVo.getId());
            if (id != null) {
                changeMapper.deleteChangeById(id);
                changeMapper.deleteChangeUserByChangeId(id);
                changeMapper.deleteChangeStepByChangeId(id);
                changeMapper.deleteChangeStepUserByChangeId(id);
                changeMapper.deleteChangeStepTeamByChangeId(id);
                changeMapper.deleteChangeStepContentByChangeId(id);
                changeMapper.deleteChangeStepFileByChangeId(id);
                changeMapper.deleteChangeDescriptionByChangeId(id);
                changeMapper.deleteChangeFileByChangeId(id);
                changeMapper.deleteChangeChangeTemplateByChangeId(id);
                changeMapper.deleteProcessTaskStepChangeHandleByChangeId(id);
                changeMapper.deleteChangeStepCommentByChangeId(id);
                changeMapper.deleteChangeAutoStartByChangeId(id);
                changeMapper.deleteChangeStepPauseOperateByChangeId(id);
            }
            return 0;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new ProcessTaskException(e);
        }
    }

    @Override
    protected int myAssign(ProcessTaskStepVo currentProcessTaskStepVo, Set<ProcessTaskStepWorkerVo> workerSet)
            throws ProcessTaskException {
        return defaultAssign(currentProcessTaskStepVo, workerSet);
    }

    @Override
    protected int myHang(ProcessTaskStepVo currentProcessTaskStepVo) {
        return 0;
    }

    @Override
    protected int myHandle(ProcessTaskStepVo currentProcessTaskStepVo) throws ProcessTaskException {
        return 0;
    }

    @Override
    protected int myStart(ProcessTaskStepVo currentProcessTaskStepVo) throws ProcessTaskException {
        return 0;
    }

    @Override
    protected int myComplete(ProcessTaskStepVo currentProcessTaskStepVo) throws ProcessTaskException {
        return myStartProcess(currentProcessTaskStepVo);
    }

    @Override
    protected int myCompleteAudit(ProcessTaskStepVo currentProcessTaskStepVo) {
        if (StringUtils.isNotBlank(currentProcessTaskStepVo.getError())) {
            currentProcessTaskStepVo.getParamObj().put(ProcessTaskAuditDetailType.CAUSE.getParamName(),
                    currentProcessTaskStepVo.getError());
        }
        /* 处理历史记录 **/
        String action = currentProcessTaskStepVo.getParamObj().getString("action");
        JSONObject handlerStepInfoObj = currentProcessTaskStepVo.getParamObj().getJSONObject("handlerStepInfo");
        if (MapUtils.isNotEmpty(handlerStepInfoObj)) {
            currentProcessTaskStepVo.getParamObj().put(ChangeAuditDetailType.CHANGEINFO.getParamName(),
                    JSON.toJSONString(handlerStepInfoObj));
        }
        IProcessStepHandlerCrossoverUtil processStepHandlerCrossoverUtil = CrossoverServiceFactory.getApi(IProcessStepHandlerCrossoverUtil.class);
        processStepHandlerCrossoverUtil.audit(currentProcessTaskStepVo, ProcessTaskAuditType.getProcessTaskAuditType(action));
        return 1;
    }

    @Override
    protected int myReapproval(ProcessTaskStepVo currentProcessTaskStepVo) throws ProcessTaskException {
        return 0;
    }

    @Override
    protected int myReapprovalAudit(ProcessTaskStepVo currentProcessTaskStepVo) {
        return 0;
    }

    @Override
    protected int myRetreat(ProcessTaskStepVo currentProcessTaskStepVo) throws ProcessTaskException {
        return myActive(currentProcessTaskStepVo);
    }

    @Override
    protected int myAbort(ProcessTaskStepVo currentProcessTaskStepVo) {
        return 0;
    }

    @Override
    protected int myRecover(ProcessTaskStepVo currentProcessTaskStepVo) {
        return 0;
    }

    @Override
    protected int myTransfer(ProcessTaskStepVo currentProcessTaskStepVo, List<ProcessTaskStepWorkerVo> workerList)
            throws ProcessTaskException {
        return 1;
    }

    @Override
    protected int myBack(ProcessTaskStepVo currentProcessTaskStepVo) throws ProcessTaskException {
        return 0;
    }

    @Override
    protected int mySaveDraft(ProcessTaskStepVo currentProcessTaskStepVo) throws ProcessTaskException {
        try {
            JSONObject paramObj = currentProcessTaskStepVo.getParamObj();
            JSONObject handlerStepInfoObj = paramObj.getJSONObject("handlerStepInfo");
            if (MapUtils.isNotEmpty(handlerStepInfoObj)) {
                String content = handlerStepInfoObj.getString("content");
                if (StringUtils.isNotBlank(content)) {
                    paramObj.put("content", content);
                }
            }
            return 1;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new ProcessTaskException(e);
        }
    }

    @Override
    protected int myStartProcess(ProcessTaskStepVo currentProcessTaskStepVo) throws ProcessTaskException {
        try {
            JSONObject paramObj = currentProcessTaskStepVo.getParamObj();
            JSONObject handlerStepInfoObj = paramObj.getJSONObject("handlerStepInfo");
            ChangeVo changeVo = JSON.toJavaObject(handlerStepInfoObj, ChangeVo.class);
            if (changeVo != null) {
                JSONArray planStartEndTime = handlerStepInfoObj.getJSONArray("planStartEndTime");
                if (CollectionUtils.isEmpty(planStartEndTime)) {
                    throw new ParamNotExistsException("handlerStepInfo.planStartEndTime");
                }
                changeVo.setId(null);
                Long id = changeMapper.getChangeIdByProcessTaskStepId(currentProcessTaskStepVo.getId());
                if (id != null) {
                    changeVo.setId(id);
                }
                changeVo.setReporter(UserContext.get().getUserUuid(true));
                changeMapper.insertChange(changeVo);
                /* 保存变更经理 **/
                String owner = changeVo.getOwner();
                if (StringUtils.isNotBlank(owner)) {
                    if (owner.contains("#")) {
                        owner = owner.split("#")[1];
                    }
                    changeMapper.insertChangeUser(changeVo.getId(), owner);
                } else {
                    throw new ParamNotExistsException("handlerStepInfo.owner");
                }
                if (id == null) {
                    /* 插入变更创建节点与变更的关系数据 **/
                    ProcessTaskStepChangeVo processTaskStepChangeVo = new ProcessTaskStepChangeVo();
                    processTaskStepChangeVo.setProcessTaskId(currentProcessTaskStepVo.getProcessTaskId());
                    processTaskStepChangeVo.setProcessTaskStepId(currentProcessTaskStepVo.getId());
                    processTaskStepChangeVo.setChangeId(changeVo.getId());
                    /* 保存变更初始化配置 **/
                    processTaskStepChangeVo.setConfig(JSON.toJSONString(handlerStepInfoObj));
                    changeMapper.insertProcessTaskStepChangeCreate(processTaskStepChangeVo);
                } else {
                    changeMapper.updateChangeConfigByChangeId(id, JSON.toJSONString(handlerStepInfoObj));
                }
                /* 保存变更描述 **/
                if (StringUtils.isNotBlank(changeVo.getContent())) {
                    ChangeContentVo contentVo = new ChangeContentVo(changeVo.getContent());
                    changeMapper.replaceChangeContent(contentVo);
                    changeMapper.insertChangeDescription(new ChangeDescriptionVo(changeVo.getId(), contentVo.getHash()));
                    paramObj.remove("content");
                }
                /* 保存变更附件 **/
                if (CollectionUtils.isNotEmpty(changeVo.getFileIdList())) {
                    for (Long fileId : changeVo.getFileIdList()) {
                        changeMapper.insertChangeFile(new ChangeFileVo(changeVo.getId(), fileId));
                    }
                }
                /* 保存变更与使用的变更模板关系 **/
                if (changeVo.getChangeTemplateId() != null) {
                    changeMapper.insertChangeChangeTemplate(changeVo.getId(), changeVo.getChangeTemplateId());
                }
                List<ChangeStepVo> changeStepList = changeVo.getChangeStepList();
                changeStepList.sort((e1, e2) -> e1.getCode().compareToIgnoreCase(e2.getCode()));
                for (ChangeStepVo changeStepVo : changeStepList) {
                    if (StringUtils.isBlank(changeStepVo.getName())) {
                        throw new ParamNotExistsException("handlerStepInfo.changeStepList[x].name");
                    }
                    /* 保存步骤信息 **/
                    changeStepVo.setChangeId(changeVo.getId());
                    changeStepVo.setId(null);
                    changeMapper.insertChangeStep(changeStepVo);
                    /* 保存描述内容 **/
                    String content = changeStepVo.getContent();
                    if (StringUtils.isNotBlank(content)) {
                        /* 替换描述内容变量 **/
                        if (MapUtils.isNotEmpty(changeVo.getParamDataMap()) && content.contains("${DATA.")) {
                            try {
                                content = FreemarkerUtil.transform(changeVo.getParamDataMap(), content);
                            } catch (FreemarkerTransformException e) {
                                logger.error(e.getMessage(), e);
                            }
                        }
                        if (StringUtils.isNotBlank(content)) {
                            ChangeContentVo contentVo = new ChangeContentVo(content);
                            changeMapper.replaceChangeContent(contentVo);
                            changeMapper.insertChangeStepContent(new ChangeStepContentVo(changeVo.getId(), changeStepVo.getId(),
                                    contentVo.getHash()));
                        }
                    }
                    /* 保存附件 **/
                    if (CollectionUtils.isNotEmpty(changeStepVo.getFileIdList())) {
                        for (Long fileId : changeStepVo.getFileIdList()) {
                            changeMapper.insertChangeStepFile(new ChangeStepFileVo(changeVo.getId(), changeStepVo.getId(),
                                    fileId));
                        }
                    }
                    /* 保存处理人或组 **/
                    String worker = changeStepVo.getWorker();
                    if (StringUtils.isNotBlank(worker) && worker.contains("#")) {
                        String[] split = worker.split("#");
                        if (GroupSearch.USER.getValue().equals(split[0])) {
                            changeMapper.insertChangeStepUser(
                                    new ChangeStepUserVo(changeVo.getId(), changeStepVo.getId(), split[1]));
                        } else if (GroupSearch.TEAM.getValue().equals(split[0])) {
                            changeMapper.insertChangeStepTeam(
                                    new ChangeStepTeamVo(changeVo.getId(), changeStepVo.getId(), split[1]));
                        }
                    } else {
                        throw new ParamNotExistsException("handlerStepInfo.changeStepList[x].worker");
                    }
                }
                /* 活动信息 **/
                // TODO linbq0127这里需要优化
                ChangeVo change = changeMapper.getChangeById(changeVo.getId());
                if (change != null) {
                    String userUuid = changeMapper.getChangeUserByChangeId(changeVo.getId());
                    if (StringUtils.isNotBlank(userUuid)) {
                        change.setOwner(userUuid);
                    }
                    String contentHash = changeMapper.getChangeDescriptionContentHashByChangeId(changeVo.getId());
                    if (StringUtils.isNotBlank(contentHash)) {
                        change.setContent(changeMapper.getChangeContentByHash(contentHash));
                    }
                    List<Long> fileIdList = changeMapper.getChangeFileIdListByChangeId(changeVo.getId());
                    if (CollectionUtils.isNotEmpty(fileIdList)) {
                        List<FileVo> fileList = fileMapper.getFileListByIdList(fileIdList);
                        if (CollectionUtils.isNotEmpty(fileList)) {
                            change.setFileList(fileList);
                            change.setFileIdList(fileList.stream().map(FileVo::getId).collect(Collectors.toList()));
                        }
                    }
                    currentProcessTaskStepVo.getParamObj().put(ChangeAuditDetailType.CHANGEINFO.getParamName(),
                            JSON.toJSONString(changeVo));
                }
            }
            return 1;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new ProcessTaskException(e);
        }
    }

    @Override
    protected Set<Long> myGetNext(ProcessTaskStepVo currentProcessTaskStepVo, List<Long> nextStepIdList, Long nextStepId) throws ProcessTaskException {
        return defaultGetNext(nextStepIdList, nextStepId);
    }

    @Override
    protected int myRedo(ProcessTaskStepVo currentProcessTaskStepVo) throws ProcessTaskException {
        return myActive(currentProcessTaskStepVo);
    }

    @Override
    protected int myPause(ProcessTaskStepVo currentProcessTaskStepVo) throws ProcessTaskException {
        return 0;
    }

}
